/**声音管理器**/
class SoundManager {
	private static _instance:SoundManager;	
	public soundDict:any;
	public static get instance():SoundManager
	{
		PoolUtil.registerClassInfo(SoundData,"SoundData");
		if(SoundManager._instance == null)
			SoundManager._instance = new SoundManager;
		return SoundManager._instance;
	}

	public channelMax:number = 5;
	private _loaddingDict:Object = {};
	private _curBGM:string;	
	private _paused:boolean;
	public enabled:boolean;
	public constructor() {
		SoundManager._instance = this;
		let s = this;		
		s.soundDict = {};
		s.enabled = true;
		
	}
	public getDefaultBgm():string
	{
		return "";//URLConf.sound + UserData.getInstance().getPlatform() + "_BGM.mp3";
	}
	public playBGM(url:string):void
	{
		let s = this;
		if(s._curBGM == url)return;
		s._curBGM = url;
		s.play(s._curBGM,0,0,null,null,SoundData.BACKGROUND_SOUND);
	}
	public closeBGM():void
	{
		let s = this;
		if(s._curBGM!=null)
		{
			s.stop(s._curBGM,SoundData.BACKGROUND_SOUND);
			s._curBGM = null;
		}
	}
	/**播放声音
	 * @param url 声音路径
	 * @param startTime 起始时间
	 * @param loops 循环次数 0为永久循环
	 * @param compF 播放完成的回调
	 * @param thisObject 回调指向
	 * @param type 声音类型 参考SoundData 常量
	 * @param isHttp 是否网络声音
	*/
	public play(url:string,startTime:number = 0, loops:number = 1, compF:Function=null, thisObject:any=null,type:number = 0):void
	{let s = this;
		if(!s.enabled)return;
		if(url == null)
		{
			console.log(MultiLang.str2 + ":" + url);
			return;
		}
		
		if(type == SoundData.COMMON_SOUND)
			s.stop();
		
		if(s.soundDict[url] == null)
		{
			if((url.indexOf("http") == 0) && GYLoader.getRes(url) == null)
			{
				let obj:any = {url:url,startTime:startTime,loops:loops,compF:compF,thisObject:thisObject,type:type};
				s._loaddingDict[url] = obj;				
				Main.instance.myLoader.loadData(url,s.loadSoundComp,s,null,GYLoader.TYPE_BINARY,"get",obj).save = false;
				return;
			}
			let res:ResObject = GYLoader.getRes(url);
			if(res)
			{
				s.soundDict[url] = PoolUtil.fromPool(SoundData);
				s.soundDict[url].sound = res.res;
			}				
			if(s.soundDict[url] == null)
			{
				if(compF!=null)
					compF.call(thisObject);
				console.warn(MultiLang.str1 + ":" + url);
				return;
			}
		}		
				
		let soundObj:SoundData = s.soundDict[url];		

		//存在正在播放的channel，证明播放同一个声音，寻找可用副本，没有则创建副本
		let sId:number = soundObj.soundID;	
		while(soundObj)
		{
			if(soundObj.channel)
			{//不空闲，下一个
				++sId;
				if(sId >= s.channelMax)//超出同类声音播放上限
					return;
				soundObj = s.soundDict[url+"?"+sId];
				if(soundObj == null)//没有找到空闲，创建一个
				{
					soundObj = s.soundDict[url].clone();
					soundObj.soundID = sId;//累加的ID
					s.soundDict[url+"?"+sId] = soundObj;
					break;
				}	
			}
			else
			{//空闲拿来用
				break;
			}
		}		

		soundObj.url = url;
		soundObj.soundType = type;		
		s.playBySoundData(soundObj, startTime, loops, compF, thisObject);		
	}
	private loadSoundComp(l:LoadInfo):void
	{let s = this;
		if(l.content == null)
		{
			if(s._loaddingDict[l.param.url].compF!=null)
				s._loaddingDict[l.param.url].compF.call(s._loaddingDict[l.param.url].thisObject);
			delete s._loaddingDict[l.param.url];
			console.warn(MultiLang.str1 + ":" + l.param.url);
			return;
		}
		if(s._loaddingDict[l.param.url] == null)return;
		let loadInfo:LoadInfo = Main.instance.myLoader.loadBytes(l.content.res, s.bytesLoaded,s,GYLoader.TYPE_SOUND,GYLoader.getMimeType(GYLoader.TYPE_SOUND),l.param);
		loadInfo.path = l.param.url;
	}
	private bytesLoaded(l:LoadInfo):void
	{let s = this;
		if(s._loaddingDict[l.param.url] == null)return;
		delete s._loaddingDict[l.param.url];
		s.play(l.param.url,l.param.startTime,l.param.loops,l.param.compF,l.param.thisObject,l.param.type);
	}
	/**播放字节流声音
	 * @param bytes 字节数组ArrayBuffer
	 * @param startTime 开始时间
	 * @param loops 循环次数 0 永久循环
	 * @param compF 结束回调函数
	 * @param thisObject this指向
	 * @param type 声音类型
	 * @param url 声音地址 
	*/
	public playBytes(bytes:ArrayBuffer,startTime:number = 0, loops:number = 1, compF:Function=null, thisObject:any=null,type:number = 0,url:string=null):void
	{
		let s = this;
		let obj:any = {url:url,startTime:startTime,loops:loops,compF:compF,thisObject:thisObject,type:type};
		let loadInfo:LoadInfo = Main.instance.myLoader.loadBytes(bytes, s.bytesSoundLoaded,s,GYLoader.TYPE_SOUND,GYLoader.getMimeType(GYLoader.TYPE_SOUND,url),obj);		
	}
	private bytesSoundLoaded(l:LoadInfo):void
	{let s = this;
		if(l.content == null)
		{			
			console.warn(MultiLang.str1 + ":" + l.param.url);
			return;
		}		
		let url:string = l.content.res.url;
		s.soundDict[url] = PoolUtil.fromPool(SoundData);
		s.soundDict[url].sound = l.content.res;
		let soundObj:SoundData = s.soundDict[url];
		soundObj.url = url;
		soundObj.soundType = l.param.type;
		s.playBySoundData(soundObj,l.param.startTime,l.param.loops,l.param.compF,l.param.thisObject);		
	}
	public playBySoundData(soundObj:SoundData,startTime:number = 0, loops:number = 1, compF:Function=null, thisObject:any=null):void
	{
		let s = this;
		let sound:Laya.Sound = soundObj.sound;		
		soundObj.compFunc = compF;
		soundObj.thisObject = thisObject;
		soundObj.position = 0;
		soundObj.loops = loops;
		if(!s._paused)
		{
			soundObj.channel = soundObj.sound.play(0,loops);			
		}	
	}
	/**停止声音，清除字典缓存
	 * @param url 声音的url，为null则是停止所有
	 * @param channelType 声道类型 -1所有的声道，0单声道 1多声道
	 * @param disposeSrc 销毁声音源数据
	 * @param soundID 声音id，同名声音的id标识 
	 * @param soundType 声音类型，0音效 1音乐 参考SoundData常量
	*/
	public stop(url:string = null,soundType:number=-1,disposeSrc:boolean=false, soundID:number=-1, ):void
	{let s = this;
		let soundObj:SoundData;
		let arr:Array<any>,arr2:Array<any>;
		let count:number=0,count2:number=0;	
		arr = [];
		for(let key in s.soundDict)
		{				
			soundObj = s.soundDict[key];
			if(url == null || soundObj.url.indexOf(url) == 0)
			{
				++count;
				if((soundObj.soundType == soundType || soundType == -1) && (soundObj.soundID == soundID || soundID == -1))
				{
					arr.push(soundObj);                    
					if(disposeSrc)
						soundObj.dispose();
					else
						soundObj.clear();                    
				}
			}                
		}
		arr2 = [];
		for(let key in s._loaddingDict)
		{			
			soundObj = s._loaddingDict[key];	
			if(url == null || soundObj.url.indexOf(url) == 0)
			{
				++count2;
				if((soundObj.soundType == soundType || soundType == -1) && (soundObj.soundID == soundID || soundID == -1))
				{
					arr2.push(soundObj);                    
					if(disposeSrc)
						soundObj.dispose();
					else
						soundObj.clear();                    
				}
			}
									
		}
		if(count + count2 > 20)
			console.warn("声音播放异常#" + count + "-" + count2);
		let len:number;
		let urlKey:string;			
		len = arr.length;
		while(--len>-1)
		{
			soundObj = arr[len];                
			urlKey = soundObj.soundID > 0?(soundObj.url+"?"+soundObj.soundID):soundObj.url;
			delete s.soundDict[urlKey];			
		}
		len = arr2.length;
		while(--len>-1)
		{		
			soundObj = arr2[len];		
			urlKey = soundObj.soundID > 0?(soundObj.url+"?"+soundObj.soundID):soundObj.url;
			delete s._loaddingDict[urlKey];
		}
	}
	/**根据声音对象关闭声音*/
	public stopBySoundData(soundData:SoundData):void
	{
		let urlKey:string;
		let s = this;		            
		urlKey = soundData.soundID > 0?(soundData.url+"?"+soundData.soundID):soundData.url;
		delete s.soundDict[urlKey];		
		delete s._loaddingDict[urlKey];		
	}
	/**暂停所有声音*/
	public pause():void
	{let s = this;
		let soundObj:SoundData;
		let arr:Array<any>;
		if(s._paused)return;
		s._paused = true;
		for(let key in s.soundDict)
		{
			soundObj = s.soundDict[key];
			if (soundObj.channel) {
				soundObj.position = soundObj.channel.position;
				soundObj.paused = true;						
				soundObj.channel = null;
				
			} else {
				soundObj.paused = false;
			}			
		}
	}
	/**恢复所有声音*/
	public resume():void
	{let s = this;
		let soundObj:SoundData;
		let arr:Array<any>;
		if(!s._paused)return;
		s._paused = false;
		for(let key in s.soundDict)
		{				
			soundObj = s.soundDict[key];			
			if (soundObj.paused) {
				if (soundObj.loops == 0) {
					soundObj.position = 0;
				}				
				soundObj.channel = soundObj.sound.play(soundObj.position, soundObj.loops);				
			}
		}
	}
	/*销毁对声音的引用
	* @param url 声音url null表示销毁全部
	* @param disposeSrc 是否销毁声音元数据
	**/
	public dispose(url:string=null,disposeSrc:boolean=false):void
	{
		let s = this;
		s.stop(url,0,disposeSrc);
	}
	// public set volume(val:number)
	// {let s = this;
	// 	if(s._curChannel == null)return;
	// 	s._curChannel.volume = val;
	// }
	// public get volume():number
	// {let s = this;
	// 	return s._curChannel?s._curChannel.volume:0;
	// }
	// public get position():number
	// {let s = this;
	// 	return s._curChannel?s._curChannel.position:0;
	// }
	// public set position(val:number)
	// {let s = this;
	// 	if(s._curChannel == null)return;
	// 	s._curChannel.position = val;
	// }
}
class SoundData implements IPoolObject
{
	public soundID:number;
	public sound:any;
	public compFunc:any;
	public thisObject:any;
	private _channel:Laya.SoundChannel;
	private _tempChannels:Laya.SoundChannel[]=[];
	public timeId:number = -1;
	public soundType:number = 0;
	public position:number;
	public loops:number;
	public url:string;
	public paused:boolean = false;
	public static COMMON_SOUND:number = 0;
	public static BACKGROUND_SOUND:number = 1;
	public clone():SoundData
	{let s = this;
		let soundData:any = PoolUtil.fromPool(SoundData);
		soundData.sound = s.sound;
		return soundData;
	}
	public soundComplete(e:Laya.Event=null):void
	{
		let s = this;		
		s.channel = null;
		if(s.compFunc != null)
		{
			if(s.compFunc.length == 1)
				s.compFunc.call(s.thisObject,s);
			else
				s.compFunc.call(s.thisObject);
		}				
	}
	public get channel():Laya.SoundChannel
	{
		return this._channel;
	}
	public set channel(val:Laya.SoundChannel)
	{let s = this;
		if(s._channel == val)return;
		if(s._channel)
		{
			if(s._channel.completeHandler)
			{
				s._channel.completeHandler.clear();
				s._channel.completeHandler = null;
			}			
			s._channel.stop();			
			// s._channel.off(Laya.Event.SOUND_COMPLETE,s,s.soundComplete);
			s._channel = null;
			let len:number;
			len = s._tempChannels.length;
			while(--len>-1)		
				s._tempChannels[len].stop();		
			s._tempChannels.length = 0;
		}
		if(val == null)
		{
			if(s.timeId > -1)
			{
                Laya.timer.clear(s,s.soundComplete);
				// GYLite.TimeManager.unTimeOut(s.timeId,s.soundComplete,s);
				s.timeId = -1;
			}			
		}		
		s._channel = val;
		if(s._channel)
			s._channel.completeHandler = Laya.Handler.create(s, s.soundComplete)
		// 	s._channel.on(Laya.Event.SOUND_COMPLETE,s,s.soundComplete);
	}

	public clear(): void
	{let s = this;
		if(s.inPool)return;		
		s.soundType = 0;
		if(s.timeId > -1)
		{		
            Laya.timer.clear(s,s.compFunc)	;
			// GYLite.TimeManager.unTimeOut(s.timeId,s.compFunc,s);
			s.timeId = -1;
		}			
		if(s.compFunc!=null)
		{			
			s.compFunc = null;
			s.thisObject = null;
		}		
        
		s.channel = null;
		
		s.sound = null;
		s.inPool = true;
		PoolUtil.toPool(this, SoundData);
	}
    public inPool: boolean;
    public outPoolInit(): void
	{	
		let s = this;		
		s.soundID = 0;
	}
	/**销毁声音，会把声音源数据销毁*/
	public dispose():void
	{
		let s = this;
		GYLoader.deleteResByKey(s.url);
		s.clear();		
	}
}